/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.ambimmort.ucagent.modules.webservice;

import cn.net.greenet.db.HibernateUtil;
import cn.net.greenet.db.bean.Dpiendpointbean;
import cn.net.greenet.db.bean.Messageoutgoingsendingqueue;
import com.ambimmort.ucagent.modules.server.codec.UcRawMessage;
import com.ambimmort.ucagent.modules.server.dpi.DPIEndPointManager;
import com.ambimmort.umessage.util.ByteConvert;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;

import java.util.*;

/**
 * @author 定巍
 */
public class WebServiceBeanImpl implements WebServiceBean {

    @Override
    public void refreshDPIEndPoint() {
        try {
            DPIEndPointManager.getInstance().refresh();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void msg_send_manaul_by_MessageTypeAndDevice(String devName, String messageType) {
        try {
            Session s = HibernateUtil.getSessionFactory().openSession();
            List<Messageoutgoingsendingqueue> l = null;
            Transaction tx = null;
            try {
                Query query = s.createQuery("SELECT msg FROM Messageoutgoingsendingqueue AS msg where msg.dpiendpointbean.name=:name and msg.messageType=:messageType and msg.type=1");
                query.setParameter("name", devName);
                query.setParameter("messageType", messageType);
                l = query.list();

                Messageoutgoingsendingqueue m = null;
                HashMap<String, List<UcRawMessage>> typeMap = new HashMap<String, List<UcRawMessage>>();
                UcRawMessage rm = null;
                for (int i = 0; i < l.size(); i++) {
                    m = (Messageoutgoingsendingqueue) l.get(i);
                    if (typeMap.containsKey(m.getMessageType())) {
                        rm = wrap(m.getPacket());
                        rm.setArg(m);
                        typeMap.get(m.getMessageType()).add(rm);
                    } else {
                        ArrayList<UcRawMessage> list = new ArrayList<UcRawMessage>();
                        rm = wrap(m.getPacket());
                        rm.setArg(m);
                        list.add(rm);
                        typeMap.put(m.getMessageType(), list);
                    }
                }

                for (String key : typeMap.keySet()) {
                    if (isVersionManaged((byte) Integer.parseInt(key.substring(key.length() - 2, key.length()), 16))) {
                        Collections.sort(typeMap.get(key), new Comparator<UcRawMessage>() {
                            @Override
                            public int compare(UcRawMessage o1, UcRawMessage o2) {
                                return (int) (getMessageSerialNo(o1) - getMessageSerialNo(o2));
                            }
                        });
                    }
                }

                for (String key : typeMap.keySet()) {
                    for (UcRawMessage msg : typeMap.get(key)) {
                        send_Manul(msg, devName);
                    }
                }
                List<Dpiendpointbean> dpis = s.createQuery("select dpi from Dpiendpointbean as dpi where dpi.name=:name").setParameter("name", devName).list();
                for (Dpiendpointbean dpi : dpis) {
                    tx = s.beginTransaction();
                    Query delete = s.createQuery("delete  Messageoutgoingsendingqueue msg where msg.dpiendpointbean=:dpi and msg.type=1");
                    delete.setParameter("dpi", dpi);
                    delete.executeUpdate();
                    tx.commit();
                }
                System.out.println("==>[Function Send Message] DONE");
            } catch (Exception e) {
                e.printStackTrace();
                if (tx != null) {
                    tx.commit();
                }
            } finally {
                if (s != null) {
                    s.close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void msg_send_manaul(String devName) {
        try {
            Session s = HibernateUtil.getSessionFactory().openSession();
            List<Messageoutgoingsendingqueue> l = null;
            Transaction tx = null;
            try {
                Query query = s.createQuery("SELECT msg FROM Messageoutgoingsendingqueue AS msg where msg.dpiendpointbean.name=:name and msg.type=1");
                query.setParameter("name", devName);
                l = query.list();
                Messageoutgoingsendingqueue m = null;
                HashMap<String, List<UcRawMessage>> typeMap = new HashMap<String, List<UcRawMessage>>();
                UcRawMessage rm = null;
                for (int i = 0; i < l.size(); i++) {
                    m = (Messageoutgoingsendingqueue) l.get(i);
                    if (typeMap.containsKey(m.getMessageType())) {
                        rm = wrap(m.getPacket());
                        rm.setArg(m);
                        typeMap.get(m.getMessageType()).add(rm);
                    } else {
                        ArrayList<UcRawMessage> list = new ArrayList<UcRawMessage>();
                        rm = wrap(m.getPacket());
                        rm.setArg(m);
                        list.add(rm);
                        typeMap.put(m.getMessageType(), list);
                    }
                }

                for (String key : typeMap.keySet()) {
                    if (isVersionManaged((byte) Integer.parseInt(key.substring(key.length() - 2, key.length()), 16))) {
                        Collections.sort(typeMap.get(key), new Comparator<UcRawMessage>() {
                            @Override
                            public int compare(UcRawMessage o1, UcRawMessage o2) {
                                if ((getMessageSerialNo(o1) == 0l) && (getMessageSerialNo(o2) == 0l)) {
                                    return (int) (o1.getMessageSequenceNo().toLong() - o2.getMessageSequenceNo().toLong());
                                } else {
                                    return (int) (getMessageSerialNo(o1) - getMessageSerialNo(o2));
                                }
                            }
                        });
                    }
                }

                System.out.println("==>[Function Send Message] Type Count: " + typeMap.keySet().size() + "\tMsg Count:" + l.size());

                List<UcRawMessage> data = new ArrayList<UcRawMessage>(); //0x40用户组归属  +  0x85用户与应用绑定
                if (typeMap.containsKey("0x40")) {
                    data.addAll(typeMap.remove("0x40"));
                } else if (typeMap.containsKey("0x85")) {
                    data.addAll(typeMap.remove("0x85"));
                }

                for (String key : typeMap.keySet()) {
                    for (UcRawMessage msg : typeMap.get(key)) {
//                        System.out.println("=>Sending Msg: messageType:" + HexUtil.getHex(msg.getMessageType().toByte()) + "\tmessageNo:" + msg.getMessageNo() + "\tmessageSequenceNo:" + msg.getMessageSequenceNo());
                        if (send_Manul(msg, devName)) {
//                            System.out.println("=>Sent Msg: messageType:" + HexUtil.getHex(msg.getMessageType().toByte()) + "\tmessageNo:" + msg.getMessageNo() + "\tmessageSequenceNo:" + msg.getMessageSequenceNo());
//                            Thing t = new Thing();
//                            t.setAction(Thing.DLETE);
//                            t.setData(msg.getArg());
//                            Cacher.getInstance().addTing(t);
//                            System.out.println("=>Delete Msg From Queue: messageType:" + HexUtil.getHex(msg.getMessageType().toByte()) + "\tmessageNo:" + msg.getMessageNo() + "\tmessageSequenceNo:" + msg.getMessageSequenceNo());
                        }
                    }
                }
                // 0x40 +  0x85
                for (UcRawMessage msg : data) {
//                    System.out.println("=>Sending Msg: messageType:" + HexUtil.getHex(msg.getMessageType().toByte()) + "\tmessageNo:" + msg.getMessageNo() + "\tmessageSequenceNo:" + msg.getMessageSequenceNo());
                    if (send_Manul(msg, devName)) {
//                        System.out.println("=>Sent Msg: messageType:" + HexUtil.getHex(msg.getMessageType().toByte()) + "\tmessageNo:" + msg.getMessageNo() + "\tmessageSequenceNo:" + msg.getMessageSequenceNo());
//                        Thing t = new Thing();
//                        t.setAction(Thing.DLETE);
//                        t.setData(msg.getArg());
//                        Cacher.getInstance().addTing(t);
//                        System.out.println("=>Delete Msg From Queue: messageType:" + HexUtil.getHex(msg.getMessageType().toByte()) + "\tmessageNo:" + msg.getMessageNo() + "\tmessageSequenceNo:" + msg.getMessageSequenceNo());
                    }
                }

                List<Dpiendpointbean> dpis = s.createQuery("select dpi from Dpiendpointbean as dpi where dpi.name=:name").setParameter("name", devName).list();
                for (Dpiendpointbean dpi : dpis) {
                    tx = s.beginTransaction();
                    Query delete = s.createQuery("delete  Messageoutgoingsendingqueue msg where msg.dpiendpointbean=:dpi and msg.type=1");
                    delete.setParameter("dpi", dpi);
                    delete.executeUpdate();
                    tx.commit();
                }
                System.out.println("==>[Function Send Message] DONE with [" + l.size() + "]");
            } catch (Exception e) {
                e.printStackTrace();
                if (tx != null) {
                    tx.rollback();
                }
            } finally {
                if (s != null) {
                    s.close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public long getMessageSerialNo(UcRawMessage msg) {
        byte[] MessageSerialNo = new byte[4];
        MessageSerialNo[0] = msg.getBody()[msg.getBody().length - 4];
        MessageSerialNo[1] = msg.getBody()[msg.getBody().length - 3];
        MessageSerialNo[2] = msg.getBody()[msg.getBody().length - 2];
        MessageSerialNo[3] = msg.getBody()[msg.getBody().length - 1];
        return ByteConvert.bytesToUint(MessageSerialNo);
    }

    private boolean isVersionManaged(byte messageType) {
        if (messageType == (byte) 0x01 || messageType == (byte) 0x02
                || messageType == (byte) 0x05 || messageType == (byte) 0x06
                || messageType == (byte) 0x07 || messageType == (byte) 0x08
                || messageType == (byte) 0x09 || messageType == (byte) 0x45
                || messageType == (byte) 0x40 || messageType == (byte) 0x42
                || messageType == (byte) 0x43 || messageType == (byte) 0x0a
                || messageType == (byte) 0xc2 || messageType == (byte) 0xc7
                || messageType == (byte) 0xc8 || messageType == (byte) 0xc9
                || messageType == (byte) 0xca || messageType == (byte) 0xcf) {
            return true;
        } else {
            return false;
        }
    }

    private UcRawMessage wrap(byte[] datas) {
        byte[] header = new byte[18];
        byte[] body = null;
        body = new byte[datas.length - 18];
        System.arraycopy(datas, 0, header, 0, 18);
        System.arraycopy(datas, 18, body, 0, body.length);
        UcRawMessage msg = new UcRawMessage();
        msg.setBody(body);
        msg.setHeader(header);
        return msg;
    }

    private boolean send_Manul(UcRawMessage msg, String devName) {

        if (DPIEndPointManager.getInstance().getByName(devName) != null) {
            return DPIEndPointManager.getInstance().getByName(devName).getClientChannel().send_Manaul(msg);
        } else {
            return false;
        }
    }

    private boolean send_System(UcRawMessage msg, String devName) {

        if (DPIEndPointManager.getInstance().getByName(devName) != null) {
            return DPIEndPointManager.getInstance().getByName(devName).getClientChannel().send_system(msg);
        } else {
            return false;
        }
    }

    //    @Override
    public void msg_send_system(String devName) {
        try {
            Session s = HibernateUtil.getSessionFactory().openSession();
            List<Messageoutgoingsendingqueue> l = null;
            Transaction tx = null;
            try {
                Query query = s.createQuery("SELECT msg FROM Messageoutgoingsendingqueue AS msg where msg.dpiendpointbean.name=:name and msg.type=0");
                query.setParameter("name", devName);
                l = query.list();
                s.close();
                Messageoutgoingsendingqueue m = null;
                HashMap<String, List<UcRawMessage>> typeMap = new HashMap<String, List<UcRawMessage>>();
                UcRawMessage rm = null;
                for (int i = 0; i < l.size(); i++) {
                    m = (Messageoutgoingsendingqueue) l.get(i);
                    if (typeMap.containsKey(m.getMessageType())) {
                        rm = wrap(m.getPacket());
                        rm.setArg(m);
                        typeMap.get(m.getMessageType()).add(rm);
                    } else {
                        ArrayList<UcRawMessage> list = new ArrayList<UcRawMessage>();
                        rm = wrap(m.getPacket());
                        rm.setArg(m);
                        list.add(rm);
                        typeMap.put(m.getMessageType(), list);
                    }
                }

                for (String key : typeMap.keySet()) {
                    if (isVersionManaged((byte) Integer.parseInt(key, 16))) {
                        Collections.sort(typeMap.get(key), new Comparator<UcRawMessage>() {
                            @Override
                            public int compare(UcRawMessage o1, UcRawMessage o2) {
                                if ((getMessageSerialNo(o1) == 0l) && (getMessageSerialNo(o2) == 0l)) {
                                    return (int) (o1.getMessageSequenceNo().toLong() - o2.getMessageSequenceNo().toLong());
                                } else {
                                    return (int) (getMessageSerialNo(o1) - getMessageSerialNo(o2));
                                }
                            }
                        });
                    }
                }

                List<UcRawMessage> data = new ArrayList<UcRawMessage>(); //0x40用户组归属  +  0x85用户与应用绑定
                if (typeMap.containsKey("0x40")) {
                    data.addAll(typeMap.remove("0x40"));
                } else if (typeMap.containsKey("0x85")) {
                    data.addAll(typeMap.remove("0x85"));
                }

                for (String key : typeMap.keySet()) {
                    for (UcRawMessage msg : typeMap.get(key)) {
                        if (send_System(msg, devName)) {
//                            Thing t = new Thing();
//                            t.setAction(Thing.DLETE);
//                            t.setData(msg.getArg());
//                            Cacher.getInstance().addTing(t);
                        }
                    }
                }
                // 0x40 +  0x85
                for (UcRawMessage msg : data) {
//                    System.out.println("=>Sending Msg: messageType:" + HexUtil.getHex(msg.getMessageType().toByte()) + "\tmessageNo:" + msg.getMessageNo() + "\tmessageSequenceNo:" + msg.getMessageSequenceNo());
                    if (send_Manul(msg, devName)) {
//                        System.out.println("=>Sent Msg: messageType:" + HexUtil.getHex(msg.getMessageType().toByte()) + "\tmessageNo:" + msg.getMessageNo() + "\tmessageSequenceNo:" + msg.getMessageSequenceNo());
//                        Thing t = new Thing();
//                        t.setAction(Thing.DLETE);
//                        t.setData(msg.getArg());
//                        Cacher.getInstance().addTing(t);
//                        System.out.println("=>Delete Msg From Queue: messageType:" + HexUtil.getHex(msg.getMessageType().toByte()) + "\tmessageNo:" + msg.getMessageNo() + "\tmessageSequenceNo:" + msg.getMessageSequenceNo());
                    }
                }
                List<Dpiendpointbean> dpis = s.createQuery("select dpi from Dpiendpointbean as dpi where dpi.name=:name").setParameter("name", devName).list();
                for (Dpiendpointbean dpi : dpis) {
                    tx = s.beginTransaction();
                    Query delete = s.createQuery("delete  Messageoutgoingsendingqueue msg where msg.dpiendpointbean=:dpi and msg.type=1");
                    delete.setParameter("dpi", dpi);
                    delete.executeUpdate();
                    tx.commit();
                }
            } catch (Exception e) {
                e.printStackTrace();
                if (tx != null) {
                    tx.rollback();
                }
            } finally {
                if (s != null) {
                    s.close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @Override
    public boolean enableDPIEndPoint(int id, boolean enable) {
        try {
            if (enable) {
                return DPIEndPointManager.getInstance().addDPIEndPoint(id);
            } else {
                return DPIEndPointManager.getInstance().removeDPIEndPoint(id);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

}
